package com.iwhalecloud.citybrain.flow.platform.manager.application.service;

import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.FormFieldLimitEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowFormExternalInfoDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.form.FormFieldLimitDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.form.FormFieldValidateRequestVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.form.FormFieldValidateResultVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowFormRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.FormService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author: liyang
 * @date: 2021/10/26 20:29
 */
@Service
@Slf4j
public class FlowFormService {

    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private FlowFormRepository flowFormRepository;

    @Autowired
    private FormService formService;

    /**
     * 根据流程实例id查询流程字段限制
     * 根据任务实例id查询节点字段限制
     *
     * @param processInstanceId
     * @param taskId
     * @return
     */
    public List<FormFieldLimitDomain> listByProcessInstanceIdOrTaskId(String processInstanceId, String taskId)
        throws Exception {
        if (StringUtils.isBlank(processInstanceId) && StringUtils.isBlank(taskId)) {
            throw new Exception("任务编号和流程编号不能都为空");
        }
        if (StringUtils.isNotBlank(taskId)) {
            List<Task> taskList = taskService.createTaskQuery().taskId(taskId).list();

            Assert.notEmpty(taskList, "根据任务实例编号未找到任务[" + taskId + "]");

            Task task = taskList.get(0);
            String formKey = task.getFormKey();
            if (StringUtils.isNotBlank(formKey)) {
                String processDefinitionId = task.getProcessDefinitionId();
                ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(processDefinitionId).singleResult();
                String formId = getFormIdByFormKey(formKey);

                List<FormFieldLimitDomain> formFieldLimitDomainList = flowFormRepository.getFormFieldLimitByNodeCode(
                    processDefinition.getDeploymentId()
                    , formId
                    , task.getTaskDefinitionKey());
                return formFieldLimitDomainList;
            } else {
                return new ArrayList<>();
            }

        } else {
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(
                processInstanceId).singleResult();
            if (Objects.isNull(processInstance)) {
                throw new Exception("根据流程实例编号无法找到流程实例[" + processInstanceId + "]");
            }

            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(
                processInstance.getProcessDefinitionId()).singleResult();
            if (processDefinition.hasStartFormKey()) {
                String formKey = formService.getStartFormKey(processDefinition.getId());
                String formId = getFormIdByFormKey(formKey);
                List<FormFieldLimitDomain> formFieldLimitDomainList = flowFormRepository.getFormFieldLimitByFlowCode(
                    processDefinition.getDeploymentId()
                    , formId
                    , processDefinition.getKey());
                return formFieldLimitDomainList;
            } else {
                return new ArrayList<>();
            }
        }
    }

    private String getFormIdByFormKey(String formKey) {
        //外置表单的数据不为空
        String formId = null;
        FlowFormExternalInfoDomain flowFormExternalInfoDomain = flowFormRepository.findExternalFormInfo(formKey);
        if (Objects.nonNull(flowFormExternalInfoDomain)) {
            formId = flowFormExternalInfoDomain.getFormId();
        } else {
            formId = flowFormRepository.findFormIdByFormKey(formKey);
        }
        return formId;
    }

    /**
     * 校验必填的表单字段是否在map中
     * @param validateRequest
     * @return
     */
    public FormFieldValidateResultVo validateFormFieldLimits(FormFieldValidateRequestVo validateRequest) {
        FormFieldValidateResultVo resultVo = new FormFieldValidateResultVo();
        resultVo.setPass(true);

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
            .processInstanceId(validateRequest.getProcessInstanceId()).singleResult();
        if (processInstance == null) {
            resultVo.setPass(false);
            resultVo.setErrorCode(ErrorCode.NOT_EXIST.errCode());
            resultVo.setMessage("根据流程实例id未找到流程实例");
        }
        ProcessDefinition processDefinition =
            repositoryService.createProcessDefinitionQuery().processDefinitionKey(processInstance.getProcessDefinitionKey())
                .latestVersion()
                .singleResult();
        if (processDefinition == null) {
            resultVo.setPass(false);
            resultVo.setErrorCode(ErrorCode.CREATE_PROCESS_INSTANCE_FAILED.errCode());
            resultVo.setMessage("根据流程编码未找到流程配置");
            return resultVo;
        }

        if (!processDefinition.hasStartFormKey()) {
            return resultVo;
        }

        // 如果流程设置了开始表单
        // 获取到流程设定的开始表单编码
        String formKey = formService.getStartFormKey(processDefinition.getId());

        if (StringUtils.isBlank(formKey)) {
            return resultVo;
        }

        String formId = flowFormRepository.findFormIdByFormKey(formKey);
        if (StringUtils.isBlank(formId)) {
            return resultVo;
        }

        String deploymentId = processDefinition.getDeploymentId();

        List<FormFieldLimitDomain> fieldLimitDomainList =
            flowFormRepository.getFormFieldLimitByFlowCode(deploymentId, formId, processDefinition.getKey());
        if (Objects.isNull(fieldLimitDomainList) || fieldLimitDomainList.isEmpty()) {
            return resultVo;
        }
        for (FormFieldLimitDomain formFieldLimitDomain : fieldLimitDomainList) {
            Integer fieldLimit = formFieldLimitDomain.getFieldLimit();
            //约束条件往右移一定的位数，再跟1做 & 运算，如果结果为1，则约束成立
            if (((fieldLimit >> FormFieldLimitEnum.REQUIRED.getBit()) & 1) == 1) {
                Map flowParamList = validateRequest.getFlowParamList();
                Map flowPassList = validateRequest.getFlowPassList();
                if ((MapUtils.isEmpty(flowParamList) || !flowParamList.containsKey(
                    formFieldLimitDomain.getFieldId()))
                    && (MapUtils.isEmpty(flowPassList) || !flowPassList.containsKey(
                    formFieldLimitDomain.getFieldId()))) {
                    resultVo.setPass(false);
                    resultVo.setErrorCode(ErrorCode.FORM_FIELD_NOT_EXIST.errCode());
                    resultVo.setMessage(ErrorCode.FORM_FIELD_NOT_EXIST.errMessage());
                    return resultVo;
                }
            }
        }
        return resultVo;
    }

}
